package com.mapforge.map.tools.tilewriting;

import java.awt.Graphics2D;
import java.awt.Point;

import com.mapforge.map.Tile;
import com.mapforge.map.TileLayer;
import com.mapforge.map.TileMap;
import com.mapforge.map.Tileset;
import com.mapforge.map.tilewriter.TileWriter;
import com.mapforge.map.tools.undo.TilePoint;
import com.mapforge.selection.ContinuousSelection;
import com.mapforge.selection.Selection;
import com.mapforge.selection.TileSelection;

/**
 * The {@link EraserTool} class writes a {@link TileMap TileMap's}
 * {@link Tileset tileset's} empty tile to the tool's {@link TileLayer
 * TileLayer.}
 * 
 * @see Tileset#getEmptyTile()
 * @author Will Morrison
 * 
 */
public class EraserTool extends AbstractTileWriterTool {
	/**
	 * The erasers size. Must be nonzero and positive.
	 */
	private int size;

	/**
	 * Constructs a new {@link EraserTool} with a size of 1.
	 */
	public EraserTool() {
		this(1);
	}

	/**
	 * Constructs a new {@link EraserTool} having the specified size.
	 * 
	 * @param size
	 *            specified size
	 */
	public EraserTool(int size) {
		super("Erase tiles");
		this.size = 1;
	}

	/**
	 * Returns the size this {@link EraserTool} performs selections at.
	 * 
	 * @see #setSize(int)
	 * @see #performSelection(Point, Point)
	 * @return size of this {@link EraserTool}
	 */
	public int getSize() {
		return size;
	}

	/**
	 * Sets the size this {@link EraserTool} performs selections at to the
	 * specified size.
	 * 
	 * @see #getSize()
	 * @see #performSelection(Point, Point)
	 * @param size
	 *            new size this {@link EraserTool} performs selections at
	 */
	public void setSize(int size) {
		if (size < 1) {
			throw new IllegalArgumentException(
					"Eraser size must be nonzero and positive");
		}
		this.size = size;
	}

	@Override
	public void beginEdit() {
		super.beginEdit();
		this.performEdit();
	}

	@Override
	public void performEdit() {
		this.validateState();
		Selection destination = performSelection(getAnchorPoint(),
				getMovingPoint());
		Tileset tileset = this.getTileMap().getTileset();
		// select empty tile in tileset for erasing
		int x = tileset.getEmptyTileIndex() % tileset.getColumns();
		int y = tileset.getEmptyTileIndex() / tileset.getRows();
		TileWriter tileWriter = this.getTileWriter();
		tileWriter.beginWrite();
		TileSelection tileSelection = new TileSelection();
		tileSelection.addPoint(new TilePoint(tileset.getEmptyTile(), x, y));
		tileWriter.writeTiles(tileSelection, destination);
		tileWriter.endWrite();
	}

	@Override
	public void paintTilePreview(Graphics2D g, Point startingPoint,
			Point currentPoint, Selection destination, TileSelection input) {
		// intentionally left blank, eraser has no preview
	}

	/**
	 * The {@link EraserTool} creates a {@link ContinuousSelection} with size
	 * equal to its know size bounded by its {@link TileMap}.
	 */
	public Selection performSelection(Point startPoint, Point currentPoint) {
		int right = currentPoint.x + this.size;
		int bottom = currentPoint.y + this.size;
		TileMap tilemap = this.getTileMap();
		// ensure selected area is within bounds of tilemap
		if (right > tilemap.getTotalHorizontalTiles()) {
			right = tilemap.getTotalHorizontalTiles() - currentPoint.x;
		} else {
			right = this.size;
		}
		if (bottom > tilemap.getTotalVerticalTiles()) {
			bottom = tilemap.getTotalVerticalTiles() - currentPoint.y;
		} else {
			bottom = this.size;
		}
		Tile emptyTile = getTileMap().getTileset().getEmptyTile();
		TileSelection selection = new TileSelection();
		for (int y = currentPoint.y; y < bottom; y++)
			for (int x = 0; x < right; x++) {
				selection.addPoint(new TilePoint(emptyTile, x, y));
			}
		return selection;
	}
}
